/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_ui.htm
 *
 * Zhiqim UI is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
 
+(function(Z)
{
/****************************************/
//“轮播图”
/****************************************/
// 1、配置举例：
// <ul id="zoomSlider">
//     <li><img src="https://www.zhiqim.com/document/inc/www/tutorial/guest.jpg"></li>
//     <li><img src="https://www.zhiqim.com/document/inc/www/tutorial/guest.jpg"></li>
//     <li><img src="https://www.zhiqim.com/document/inc/www/tutorial/guest.jpg"></li>
//     <li><img src="https://www.zhiqim.com/document/inc/www/tutorial/guest.jpg"></li>
// </ul>
//
// <script>
//     var newZslider = new Z.Zslider(); 
//     newZslider.elem = Z("#zoomSlider");          // 列表对象
//     newZslider.width = -1;                        // 容器宽度，默认为 -1，动态计算
//     newZslider.hasBtn = true;                     // 左右按钮是否显示，默认为 true
//     newZslider.slideStyle = "slide";              // 播放类型：slide（滑动）fade（渐显），默认为 slide
//     newZslider.tabStyle = "disc";                 // tab 菜单类型：disc（实心圆点）circle（空心圆）square（实心方块），默认为 disc
//     newZslider.tabEvent = "click";                // tab 菜单触发方式：click（点击）hover（悬浮），默认为 click
//     newZslider.execute();
// </script>

Z.Zslider = Z.Class.newInstance();
Z.Zslider.prototype = 
{
    //start of Z.Zslider.prototype
    defaults: 
    {//定义
        elem: null,               // 列表对象
        width: 0,                  // 容器宽度
        height: 300,               // 容器高度
        
        hasBtn: true,             // 左右按钮是否显示，默认为 true
        doResize: false,          // 是否自适应缩放
        slideStyle: "slide",      // 播放类型：slide（滑动）fade（渐显），默认为 slide
        tabStyle: "disc",         // tab 菜单类型：disc（实心圆点）circle（空心圆）square（实心方块），默认为 disc
        tabEvent: "click",        // tab 菜单触发方式：click（点击）hover（悬浮）

        playGapless: true,        // 无缝轮播
        playAuto: true,           // 设定自动滚动
        playSpeed: 4000,          // 播放间隔
        playDuration: 800,        // 动画时长
    },
    init: function()
    {//初始化
    },
    validate: function()
    {//验证参数
        this.$ul = Z.$elem(this.elem, "Z.Zslider");
        
        if (!Z.AR.contains(["slide", "fade"], this.slideStyle))
            return false;
            
        if (!Z.AR.contains(["disc", "circle", "square"], this.tabStyle))
            return false;
        
        if (!Z.AR.contains(["click", "hover"], this.tabEvent))
            return false;
        
        return true;
    },
    execute: function()
    {//执行
        //1：检验、设置参数
        if (!this.validate())
            return;
            
        
        this.height = this.getRectSize(this.height, this.$ul.offsetHeight());
        if (this.width)
        {
            this.doResize = false;
            this.width = this.getRectSize(this.width, this.$ul.offsetWidth());
        } else {
            this.width = Math.round(this.$ul.offsetWidth());
        }
        
        if (this.playSpeed < this.playDuration){
            this.playSpeed = this.playDuration;
        }
        
        if (!this.width || !this.height)
            return Z.alert("[Z.Zslider]参数[width][height]设置有误！");
            
        //2：重新组装排版
        var wrapHtml = '<div class="z-slider z-relative" style="width:'+this.width+'px;height:'+this.height+'px;">';
        wrapHtml +=         '<div class="z-sliderList z-absolute z-w100p z-h100p z-overflow-hidden"></div>';
        wrapHtml +=         '<div class="z-sliderTab z-sliderTab-'+this.tabStyle+' z-w100p z-h0 z-absolute z-l0 z-b0 z-text-center"></div>';
        wrapHtml +=     '</div>';
        
        this.$wrap = Z(wrapHtml).insertAfter(this.$ul);
        this.$list = this.$wrap.find(".z-sliderList").append(this.$ul);
        this.$$items = this.$ul.find("li");
        this.$tab = this.$wrap.find(".z-sliderTab");
        
        this.length = this.$$items.length;
        
        //3：左右操作按钮
        if (this.hasBtn){
            var btnHtml = '<div class="z-sliderBtn z-w100p z-h0 z-absolute z-l0 z-text-center">';
            btnHtml +=         '<div class="z-sliderBtn-prev z-absolute z-l0 z-t0 z-w60 z-h100 z-pointer">';
            btnHtml +=             '<i class="z-font z-text-gray z-arrowhead-left z-absolute z-l0 z-r0 z-mg-lr-auto"></i>';
            btnHtml +=         '</div>';
            btnHtml +=         '<div class="z-sliderBtn-next z-absolute z-r0 z-t0 z-w60 z-h100 z-pointer">';
            btnHtml +=             '<i class="z-font z-text-gray z-arrowhead-right z-absolute z-l0 z-r0 z-mg-lr-auto"></i>';
            btnHtml +=         '</div>';
            btnHtml +=     '</div>';
            this.$btn = Z(btnHtml).appendTo(this.$wrap);
            this.$btn.find(".z-sliderBtn-prev").on("click", this.sliderPrev, this);
            this.$btn.find(".z-sliderBtn-next").on("click", this.sliderNext, this);
        }
        
        //4：底部导航 tab 按钮
        var tabsHtml = "";
        var i = 0;
        for (i;i < this.length;i++){
            tabsHtml += '<div></div>';
        }
        this.$tab[0].insertAdjacentHTML("beforeend",tabsHtml);
        this.$$tabs = this.$tab.find("div");
        Z(this.$$tabs[0]).addClass("z-active");
        
        //5：list 样式
        if (this.slideStyle === "slide")
        {//滑动处理
            this.$ul.css("width", this.length * this.width).css("transition-duration",this.playDuration+"ms");
            var $item;
            for (i = 0;i < this.length;i++)
            {
                $item = this.$$items[i];
                Z($item).css({
                    "width": this.width,
                    "transform": "translate3d(" + i * this.width + "px,0,0)"
                });
                if (i === 0){
                    this.$firstClone = Z($item.cloneNode("deep")).css("transform","translate3d(" + this.length * this.width + "px,0,0)");
                }
                if (i === this.length - 1){
                    this.$lastClone = Z($item.cloneNode("deep")).css("transform","translate3d(-" + this.width + "px,0,0)");
                }
            }
            
            //插入克隆体
            this.$firstClone.appendTo(this.$ul);
            this.$lastClone.appendTo(this.$ul);
            
            //滑动结束，判断是否可滑动
            this.$ul.on(this.transitionFixed(), this.slideEnd, this);
        }
        else if (this.slideStyle === "fade")
        {//渐显处理
            this.$$items.css("top","0").css("transition-property","opacity,top");
            Z(this.$$items[0]).css("opacity",1).siblings("li").css("opacity",0).addClass("z-hide");
            
            //渐隐结束，隐藏该元素
            this.$$items.on(this.transitionFixed(), this.fadeEnd, this);
        }
        this.$$items.css("transition-duration",this.playDuration+"ms");
        Z(this.$$items[0]).addClass("z-active");
        
        //6：绑定事件
        var tabEvent = (this.tabEvent === "click")?"click":"mouseenter";
        this.$$tabs.on(tabEvent, this.tabTrigger, this);
        this.$wrap.on("mouseenter", this.wrapEnter, this);
        this.$wrap.on("mouseleave", this.wrapLeave, this);
        if (this.doResize)
            Z(window).on('resize', this.resize, this);
        
        //7：开始执行动画
        this.autoPlay();
    },
    autoPlay: function()
    {//自动播放
        if(this.playAuto && !this.playAutoTimer)
            this.playAutoTimer = setInterval(this.sliderNext, this.playSpeed, null, this);
    },
    wrapEnter: function()
    {
        if(this.$btn){
            this.$btn.addClass("z-active");
        }
        //清除自动
        clearInterval(this.playAutoTimer);
        this.playAutoTimer = null;
    },
    wrapLeave: function()
    {
        if(this.$btn){
            this.$btn.removeClass("z-active");
        }
        this.autoPlay();
    },
    sliderNext: function(event, thisObj)
    {//后一个展示
        thisObj = thisObj || this;
        thisObj.sliderPlay(1);
    },
    sliderStay: function ()
    {//保持展示
        this.sliderPlay(0);
    },
    sliderPrev: function()
    {//前一个展示
        this.sliderPlay(-1);
    },
    sliderPlay: function(step)
    {//播放方法
        if (this.sliding){
            return;
        }
        this[this.slideStyle+"ToPlay"](step);
    },
    slideToPlay: function(step)
    {//滑动方法
        this.sliding = true;
        
        step = +step;
        var $activeItem = this.$ul.find(".z-active");
        var activeIndex = Z.AR.indexOf(this.$$items, $activeItem[0]);
        $activeItem.removeClass("z-active");
        
        //即将展示对象的索引值
        var shouldIndex = activeIndex + step;
        if (shouldIndex >= this.length) shouldIndex = 0;
        if (shouldIndex <= -1) shouldIndex = this.length - 1;
        
        //定义定位
        var $shouldActive = Z(this.$$items[shouldIndex]);
        var ulTrans = -shouldIndex * this.width;

        //逐步滚动 |step| = 1 到边缘时，实现无缝滚动
        if (this.playGapless)
        {
            if (step === 1 && shouldIndex === 0) {
                $shouldActive = this.$firstClone;
                ulTrans = -this.length * this.width;
            }
            if (step === -1 && shouldIndex === this.length - 1) {
                $shouldActive = this.$lastClone;
                ulTrans = this.width;
            }
        }
        // 新定位
        this.$ul.css("transform", "translate3d("+ulTrans+"px,0,0)");
        if (this.$ul.css("transition-property") === "none"){
           this.$ul.css("transition-property", "transform");
        }
        $shouldActive.addClass("z-active");
        
        //tab 展示
        Z(this.$$tabs[shouldIndex]).addClass("z-active").siblings("div").removeClass("z-active");
    },
    fadeToPlay: function(step)
    {//渐显方法
        step = +step;
        var $activeItem = this.$ul.find(".z-active");
        var activeIndex = Z.AR.indexOf(this.$$items, $activeItem[0]);
        $activeItem.removeClass("z-active").css("opacity",0).css("top",-10);
        
        var shouldIndex = activeIndex + step;
        if (shouldIndex >= this.length) shouldIndex = 0;
        if (shouldIndex <= -1) shouldIndex = this.length - 1;
        var $shouldActive = Z(this.$$items[shouldIndex]);
        $shouldActive.removeClass("z-hide").addClass("z-active").css("opacity",1);
        
        //tab 展示
        Z(this.$$tabs[shouldIndex]).addClass("z-active").siblings("div").removeClass("z-active");
    },
    fadeEnd: function(ev)
    {
        var $thisItem = Z(Z.E.current(ev));
        if (!$thisItem.hasClass("z-active")){
            $thisItem.addClass("z-hide").css("top",0);
        }
    },
    slideEnd: function(ev)
    {
        //判断是否处于 list 边缘
        var $activeItem = this.$ul.find(".z-active");
        var activeIndex = Z.AR.indexOf(this.$$items, $activeItem[0]);
        if (activeIndex > -1){
            return this.sliding = false;
        }
        $activeItem.removeClass("z-active");
        //无缝播放
        if (this.playGapless)
        {
            this.$ul.css("transition-property","none");
            if ($activeItem[0] === this.$firstClone[0]){
               this.$ul.css("transform","translate3d(0,0,0)");
               Z(this.$$items[0]).addClass("z-active");
            }
            if ($activeItem[0] === this.$lastClone[0]){
               this.$ul.css("transform","translate3d(-"+(this.length - 1) * this.width+"px,0,0)");
               Z(this.$$items[this.length - 1]).addClass("z-active");
            }
        }
        this.sliding = false;
    },
    tabTrigger: function(ev)
    {//tab 触发
        var $activeTab = this.$tab.find(".z-active");
        var activeIndex = Z.AR.indexOf(this.$$tabs, $activeTab[0]);
        
        var $shouldTab = Z(Z.E.current(ev));
        var shouldIndex = Z.AR.indexOf(this.$$tabs, $shouldTab[0]);
        
        var step = shouldIndex - activeIndex;
        this.sliderPlay(step);
    },
    resize: function()
    {
        // 停止自动播放
        this.sliding = true;
        if (this.playAutoTimer)
        {
            clearInterval(this.playAutoTimer);
            this.playAutoTimer = null;
        }

        // 设置延迟，自动播放
        if (!this.resizeStep)
            this.resizeStep = 0;
        this.resizeStep++;
        if (this.delayAutoPlay)
            clearTimeout(this.delayAutoPlay);
        this.delayAutoPlay = setTimeout(this.delayResize, this.playDuration, this, this.resizeStep);

        // 重置大小
        this.$wrap.css('width', 'auto');
        this.width = this.$wrap.offsetWidth();
        this.$wrap.css({
            "width": this.width,
        });
        this.$ul.css("width", this.length * this.width);
        this.$ul.find('li').css('width', this.width);
        for (var i = 0;i < this.length;i++) {
            Z(this.$$items[i]).css({"transform": "translate3d(" + i * this.width + "px,0,0)"});
        }
        this.$firstClone.css({"transform": "translate3d(" + this.length * this.width + "px,0,0)"});
        this.$lastClone.css({"transform":"translate3d(-" + this.width + "px,0,0)"});

        // 定位当前
        var $activeItem = this.$ul.find(".z-active");
        var activeIndex = Z.AR.indexOf(this.$$items, $activeItem[0]);
        var ulTrans = -activeIndex * this.width;
        this.$ul.css("transform", "translate3d("+ ulTrans +"px,0,0)");
    },
    delayResize: function(thisObj, resizeStep)
    {
        clearTimeout(thisObj.delayAutoPlay);
        if (resizeStep !== thisObj.resizeStep)
            return;

        thisObj.resizeStep = null;
        thisObj.autoPlay();
    },
    transitionFixed: function()
    {//兼容写法
        var $div = document.createElement('div');
        if ($div.style["transition"] !== undefined ){
            $div = null;
            return "transitionend";
        }
        if ($div.style["OTransition"] !== undefined ){
            $div = null;
            return "oTransitionEnd";
        }
        if ($div.style["WebkitTransition"] !== undefined ){
            $div = null;
            return "webkitTransitionEnd";
        }
    },
    
    getRectSize: function(val, all)
    {    
        if (/^\d+(\.\d+)?%$/.test(val))
        {
            val = parseFloat(val) / 100 * all;
        }
        else
        {
            val = parseFloat(val) || all;
            if (val < 0)
                val = all;
        }
        return Math.round(val);
    },
    //end of Z.Zslider.prototype
}

//END
})(zhiqim);